/*
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * This file is part of Harmattan SmashMiner OpenGL game application.
 * 
 * Harmattan SmashMiner OpenGL Example Application version 1.0.0
 *  
 * Latest update: 15.4.2011
 *
 * The Harmattan SmashMiner OpenGL example application demonstrates how to use 
 * the OpenGL ES in Harmattan devices.
 *
 * This example is provided as a starting point for 3rd party
 * developers (you) to ease the implementation of OpenGL based 
 * games. Ideas, parts of code or methodologies that this
 * example application uses can be freely used without restrictions.
 *
 * See file README.txt how to build and compile this example application
 * in the Harmattan SDK environment. 
 * 
 * See file INSTALL.txt to find out what is required to run this
 * application and how to install the application to the device or
 * alternatively in QEMU-emulator.
 *
 * The LICENSE.txt file explains the license this software is provided
 * with. A copy of the same license is included in this source file.
 * 
 */

/*
 * Copyright (C) 2011 by Nokia Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/// \file gamewidget.h

#ifndef GAMEWIDGET_H
#define GAMEWIDGET_H

//QT
#include <QGLWidget>
#include <QTime>
#include <QFile>

//STL
#include <fstream>

//Own
#include "defines.h"     // include this before anything else.
#include "gameengine.h"
#include "shaderprograms.h"
#ifdef SMASHMINER_CONFIG_ENABLE_ROTATION_SENSOR
#include "rotationsensor.h"
#endif
#ifdef SMASHMINER_CONFIG_ENABLE_ACCELERATION_SENSOR
#include "accelometersensor.h"
#endif
#include "musicplayer.h"
#include "particledata.h"

class GameObject;
class Asteroid;
class MeteorShower;
class Comet;
class Ufo;
class Collectible;
class GameSettings;
class SoundEngine;
class RotatingCollectible;
class QTextStream;

/*! \def MSECS_BUFF_SIZE
    Size of an array for storing time measurements (see \c GameWidget::millisecondsArray)  
*/
#define MSECS_BUFF_SIZE     3

/*! \def MSECS_BUFF_SIZE
    Initial value for time measurement.
    40 ms -> 25 fps (this is for timestep measurement at start-up). 
    See \c GameWidget::millisecondsArray
*/
#define MSECS_BUFF_DEFAULT_VALUE    40      // 40 ms -> 25 fps (this is for timestep measurement at start-up).

/*! \def SPACESHIP_CONE_INDICES
    Number of indices in the array describing the OpenGL model for space ship in the cone mode. 
*/
#define SPACESHIP_CONE_INDICES      72

/*! \def SPACESHIP_BALL_INDICES
    Number of indices in the array describing the OpenGL model for space ship in the ball mode. 
*/
#define SPACESHIP_BALL_INDICES      72

/*! \def ASTEROID_INDICES
    Number of indices in the array describing the OpenGL model for large asteroid.
*/
#define ASTEROID_INDICES            108

/*! \def ASTEROID_MEDIUM_INDICES
    Number of indices in the array describing the OpenGL model for medium sized asteroid.
*/
#define ASTEROID_MEDIUM_INDICES     54

/*! \def MINERAL_INDICES
    Number of indices in the array describing the OpenGL model for mineral.
*/
#define MINERAL_INDICES             72

/*! \def UFO_COLOR1_INDICES
    Number of indices in the array describing the OpenGL model for UFO (color 1).
*/
#define UFO_COLOR1_INDICES      144

/*! \def UFO_COLOR2_INDICES
    Number of indices in the array describing the OpenGL model for UFO (color 2).
*/
#define UFO_COLOR2_INDICES      144

/*! \def UFO_LIGHTS_INDICES
    Number of indices in the array describing the OpenGL model for UFO lights.
*/
#define UFO_LIGHTS_INDICES       36

/*! \def MISSILE_INDICES
    Number of indices in the array describing the OpenGL model for missile.
*/
 #define MISSILE_INDICES         72

/*! \def BG_GRID_X_SIZE
    Size of background grid for X axle.
*/
#define BG_GRID_X_SIZE  16

/*! \def BG_GRID_Y_SIZE
    Size of background grid for Y axle.
*/
#define BG_GRID_Y_SIZE  10

/*! \struct TextureData
 *
    Data structure for storing data for OpenGL texture objects.

    \c GameWidget class has methods for initializing texture data, e.g. 
    \c GameWidget::GLes2InitTextureBomb().
*/
struct TextureData
{
    /// Index for texture data in \c GameWidget::textureNames
    TextureIndex name;

    /// Width of the texture
    GLfloat width;
    /// Height of the texture
    GLfloat height;

    /// Vertex data for texture
    std::vector<GLfloat> vertexData;
    /// Coordinate data for texture
    std::vector<GLfloat> textureCoordinateData;
};

/*! \struct CometTextureData
    Data structure for comet texture data.
*/
struct CometTextureData
{
    /// Index of comet texture
    TextureIndex name;

    /// Vertex data for texture.
    std::vector<GLfloat> vertexData;
    /// Coordinate data for texture
    std::vector<GLfloat> textureCoordinateData;
    /// Number of comet vertixes
    int numberOfVertices;
};

class GameWidget : public QGLWidget
{
    Q_OBJECT

public:

    GameWidget(GameSettings *settings); // Giving parent to QGLWidget causes the Widget not to be drawn.
    ~GameWidget();

    /// Is the game paused
    inline bool paused() const { return isPaused; }

    /// Sets if the main menu active (true) or inactive (false)
    inline void setMainMenuActive(bool active) { isMainMenuActive = active; }

    void initTimeMeasurement();
    void initNewGame();

    SoundEngine *getSoundEngine();

    void switchPauseMode();

signals:

    void gameModeExited();      // go to "main menu" during pause mode.

    void pauseModeEntered();
    void pauseModeExited();

    void gameOver(int score, FPtype gameTime);

public slots:

    void gameOverMode(int score, FPtype gameTime);

    void setLeftHandedness(bool leftHanded);
    void setRewindEnabled(bool rewindEnabled);

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    void setBackGroundImage(int level);

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

protected:

    void resizeGL(int width, int height);

    void initializeGL();
    void setViewRanges();
    void initObjects();

    void paintGL();

    void mousePressEvent(QMouseEvent *event);

    void shipModeButtonPressed();
    void bombButtonPressed();
    void hyperJumpButtonPressed();

#ifdef SMASHMINER_CONFIG_ENABLE_DESKTOP_CONTROLS

    void mouseMoveEvent(QMouseEvent *event);

    FPtype mouseSteeringX;
    FPtype mouseSteeringY;

#endif  // SMASHMINER_CONFIG_ENABLE_DESKTOP_CONTROLS

#ifdef SMASHMINER_CONFIG_ENABLE_TESTINGMODE

    void testingModeInit();
    void testingModeSteering(FPtype time);

#endif  // SMASHMINER_CONFIG_ENABLE_TESTINGMODE

private:

    void sensorReadings();

//////////////////////////////////////////////////////////////////////////

#ifndef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    // "plain" OpenGL related:
    //^^^^^^^^^^^^^^^^^^^^^^^^^
    // see gamewidget_GL.cpp for implementation.

    void GLInitialize();
    void GLSetupViewPort();

    void GLInitBackGround();

    void GLPaint(GLfloat);

    void GLPaintBackGround();

    // methods for painting wrapping objects:
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    void GLPaintSpaceShip(GLfloat, GLfloat);
    void GLPaintAsteroid(GLfloat, GLfloat, Asteroid *);
    void GLPaintCollectible(GLfloat, GLfloat, Collectible *);
    void GLPaintRotatingCollectible(GLfloat, GLfloat, RotatingCollectible *);

    // methods for painting non-wrapping objects:
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    void GLPaintUfo(GLfloat, GLfloat, Ufo *);
    void GLPaintComet(GLfloat, GLfloat, Comet *, GLfloat);
    void GLPaintMeteorShower(GLfloat, GLfloat, MeteorShower *, GLfloat);

    void GLPaintParticles(GLfloat);

    void GLPaintObjectRadius(GameObject *);

#ifdef SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    void GLPaintControlGauges();

#ifdef SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE

    void GLPaintRewindGauge();

#endif  // SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE
#endif  // SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    void GLDrawTriangles(GLfloat *, GLfloat *, int);
    void GLCleanup();

    /// For storing background graphics (grid) for ''plain'' OpenGL mode
    std::vector<GLfloat> backgroundData;

#else   // SMASHMINER_CONFIG_USE_OPENGL_ES_2

    // OpenGL ES 2 related:
    //^^^^^^^^^^^^^^^^^^^^^^
    // see gamewidget_GLes2.cpp for implementation.

    void GLes2Initialize();
    void GLes2SetupViewPort();

    void GLes2LoadBackGroundTexture(int level);
    void GLes2InitBackGround();

    void GLes2InitTexture(const QImage &image, TextureData &textureData);

    void GLes2InitTextureBomb();
    void GLes2InitTextureHyperJump();
    void GLes2InitTextureNumbers();
    void GLes2InitTextureBigNumbers();
    void GLes2InitTextureLetterX();
    void GLes2InitTextureLetterColon();
    void GLes2InitTextureMiner();
    void GLes2InitTextureRewindR();
    void GLes2InitTextureTime();
    void GLes2InitTextureGetReady();
    void GLes2InitTextureLevel();
    void GLes2InitTextureLevelSmall();
    void GLes2InitTextureGameOver();
    void GLes2InitTexturePaused();
    void GLes2InitTextureButtonPause();
    void GLes2InitTextureButtonPlay();
    void GLes2InitTextureButtonModeBall();
    void GLes2InitTextureButtonModeCone();
    void GLes2InitTextureButtonBomb();

    void GLes2InitCometTexture();
    void GLes2ScaleCometTexture(GLfloat length, GLfloat width);// mites rewind homma hoidetaan???

    void GLes2Paint(GLfloat timestep);

#ifdef SMASHMINER_CONFIG_ENABLE_HYPERJUMP_DESTINATION_VISUALIZATION
    void GLes2PaintHJDestinations();
#endif

    void GLes2PaintBackGround();

    // methods for painting wrapping objects:
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    void GLes2PaintSpaceShip(GLfloat positionX, GLfloat positionY);
    void GLes2PaintAsteroid(GLfloat positionX, GLfloat positionY, Asteroid *asteroid);
    void GLes2PaintCollectible(GLfloat positionX, GLfloat positionY, Collectible *collectible);
    void GLes2PaintRotatingCollectible(GLfloat positionX, GLfloat positionY, RotatingCollectible *collectible);

    // methods for painting non-wrapping objects:
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    void GLes2PaintUfo(GLfloat positionX, GLfloat positionY, Ufo *ufo);
    void GLes2PaintMissile(GLfloat positionX, GLfloat positionY, Missile *missile);
    void GLes2PaintComet(GLfloat positionX, GLfloat positionY, Comet *comet, GLfloat currentTime);
    void GLes2PaintMeteorShower(GLfloat positionX, GLfloat positionY, MeteorShower *meteorShower, GLfloat currentTime);

    void GLes2PaintParticles(GLfloat timestep);

    void GLes2PaintTexture(TextureData *textureData, GLfloat positionX, GLfloat positionY, GLfloat positionZ);
    void GLes2PaintTextureBlackHole(TextureData *textureData, GLfloat positionX, GLfloat positionY, GLfloat positionZ);

    void GLes2PaintTextureNumber(int number, GLfloat positionX, GLfloat positionY);
    void GLes2PaintTextureBigNumber(int number, GLfloat positionX, GLfloat positionY);
    void GLes2PaintTextureLetterX(GLfloat positionX, GLfloat positionY);
    void GLes2PaintTextureLetterColon(GLfloat positionX, GLfloat positionY);
    void GLes2PaintTextureMiner(GLfloat positionX, GLfloat positionY);

    void GLes2PaintMinersCountStyle1(int count);
    void GLes2PaintMinersCountStyle2(int count);
    void GLes2PaintHyperJumpsCount(int count);
    void GLes2PaintBombsCount(int count);
    void GLes2PaintScore();
    void GLes2PaintLevel();
    void GLes2PaintTime();

    void GLes2PaintTextureRewindR();
    void GLes2PaintTextureGetReady();
    void GLes2PaintTextureNewLevel();
    void GLes2PaintTextureGameOver();
    void GLes2PaintTexturePaused();
    void GLes2PaintTextureButtonPause();
    void GLes2PaintTextureButtonPlay();
    void GLes2PaintTextureButtonModeBall();
    void GLes2PaintTextureButtonModeCone();
    void GLes2PaintTextureButtonBomb(GLfloat positionX, GLfloat positionY);

#ifdef SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    void GLes2PaintControlGauges();

#ifdef SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE

    void GLes2PaintRewindGauge();

#endif  // SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE
#endif  // SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    void GLes2MakeLightMaterialData(QVector4D &lightVector, GLfloat *materialColour, 
                                    QVector4D &lightMaterialVector);
    void GLes2Cleanup();
    void GLes2CompileGLSL(QGLShader *shader, const char *program, const char *name);

    /// Projection matrix for translating object coordinates to screen viewport coordinates.
    QMatrix4x4 pmvMatrix;

    /// Values for ambient light effect (set in GameWidget::GLes2Initialize()).
    QVector4D lightAmbient;
    /// Values for diffuse light effect (set in GameWidget::GLes2Initialize()).
    QVector4D lightDiffuse;
    /// Global light direction vector.
    QVector3D lightPosition;

#ifdef SMASHMINER_CONFIG_USE_OPENGL_ES_2

    QGLShader *vertexShaderSimple;

    QGLShader *vertexShaderBackground;
    QGLShader *vertexShaderBackgroundEffect2D;

    QGLShader *vertexShaderConstantMaterial;
    QGLShader *vertexShaderConstantMaterialEffect3D;

    QGLShader *vertexShaderConstantMaterialSpecular;
    QGLShader *vertexShaderConstantMaterialSpecularEffect3D;

    QGLShader *vertexShaderVariableMaterial;
    QGLShader *vertexShaderVariableMaterialEffect3D;

    QGLShader *vertexShaderParticles;
    QGLShader *vertexShaderParticlesEffect2D;

    QGLShader *vertexShaderTexture;
    QGLShader *vertexShaderTextureEffect3D;

    QGLShader *fragmentShaderRedOnly;
    QGLShader *fragmentShaderGreenOnly;
    QGLShader *fragmentShaderBlueOnly;

    QGLShader *fragmentShaderBackGround;
    QGLShader *fragmentShaderBackGroundEffect;

    QGLShader *fragmentShaderMaterial;

    QGLShader *fragmentShaderParticles;

    QGLShader *fragmentShaderTexture;

    /// Shader program for rendering background graphics
    spBackGround *programBackground;
    /// Shader program for rendering background graphics with bomb and/or effects
    spBackGroundEff2D *programBackgroundEffect2D;

    /// Shader program for rendering constant material (unified colour) game objects
    spConstantMaterial *programConstantMaterial;
    /// Shader program for rendering constant material game objects with black hole effect
    spConstantMaterialEff3D *programConstanMaterialEffect3D;

    /// Shader program for rendering constant material game objects with specular light effect
    spConstantMaterial *programConstantMaterialSpecular;
    /*! Shader program for rendering constant material game objects with specular light effect and
        black hole
     */
    spConstantMaterialEff3D *programConstantMaterialSpecularEffect3D;

    /// Shader program for rendering variable material (colour value for each vertex point) game objects
    spVariableMaterial *programVariableMaterial;
    /*! Shader program for rendering variable material (colour value for each vertex point) 
     * game objects with black hole effect
     */
    spVariableMaterialEff3D *programVariableMaterial3D;

    /// Shader program for rendering particle effects
    spParticles *programParticles;
    /// Shader program for rendering particle effects with black hole effect
    spParticlesEff2D *programParticlesEffect2D;

    /// Shader program for rendering texture objects
    spTexture *programTexture;
    /// Shader program for rendering texture objects with black hole effect
    spTextureEff3D *programTextureEffects3D;

#endif // SMASHMINER_CONFIG_USE_OPENGL_ES_2

#ifdef SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    /// Shader program for rendering control cauges 
    spControlGauges *programControlCauges;

#ifdef SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE

    /// Shader program for rendering the rewind cauge 
    spRewindGauge *programRewindCauge;

#endif  // SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE
#endif  // SMASHMINER_CONFIG_ENABLE_CONTROL_GAUGES

    QVector4D spaceshipConeAmbientLmData;
    QVector4D spaceshipConeDiffuseLmData;

    QVector4D spaceshipBallAmbientLmData;
    QVector4D spaceshipBallDiffuseLmData;

    QVector4D ufoColor1AmbientLmData;
    QVector4D ufoColor1DiffuseLmData;

    QVector4D ufoColor2AmbientLmData;
    QVector4D ufoColor2DiffuseLmData;

    QVector4D ufoLightsAmbientLmData;
    QVector4D ufoLightsDiffuseLmData;

    QVector4D mineralALightsAmbientLmData;
    QVector4D mineralALightsDiffuseLmData;

    QVector4D mineralBLightsAmbientLmData;
    QVector4D mineralBLightsDiffuseLmData;

    QVector4D mineralCLightsAmbientLmData;
    QVector4D mineralCLightsDiffuseLmData;

    QVector4D mineralDLightsAmbientLmData;
    QVector4D mineralDLightsDiffuseLmData;

    /// Stores data for ambient light effect for missile material
    QVector4D missileLightsAmbientLmData;
    /// Stores data for diffuse light effect for missile material
    QVector4D missileLightsDiffuseLmData;

    int backgroundImageOriginalWidth;
    int backgroundImageOriginalHeight;
    std::vector<GLfloat> backgroundData2x;

    int backgroundVertexDataCount;

    int backgroundTextureCoordinateDataStartIndex;
    int backgroundTextureCoordinateDataCount;

    /// Number images for OpenGL number textures for numbers 0...9.
    QImage numberImages[10];

    /// For storing OpenGL textures using indices defined in \c ::TextureIndex.
    GLuint textureNames[NumberOfTextures];

    TextureData *texBombData;
    TextureData *texHyperJumpData;
    TextureData *texNumber0Data;
    TextureData *texNumber1Data;
    TextureData *texNumber2Data;
    TextureData *texNumber3Data;
    TextureData *texNumber4Data;
    TextureData *texNumber5Data;
    TextureData *texNumber6Data;
    TextureData *texNumber7Data;
    TextureData *texNumber8Data;
    TextureData *texNumber9Data;
    TextureData *texBigNumber0Data;
    TextureData *texBigNumber1Data;
    TextureData *texBigNumber2Data;
    TextureData *texBigNumber3Data;
    TextureData *texBigNumber4Data;
    TextureData *texBigNumber5Data;
    TextureData *texBigNumber6Data;
    TextureData *texBigNumber7Data;
    TextureData *texBigNumber8Data;
    TextureData *texBigNumber9Data;
    TextureData *texLetterXData;
    TextureData *texLetterColonData;
    TextureData *texMinerData;
    TextureData *texRewindRData;
    TextureData *texTimeData;
    TextureData *texGetReadyData;
    TextureData *texLevelData;
    TextureData *texLevelSmallData;
    TextureData *texGameOverData;
    TextureData *texPausedData;
    TextureData *texButtonPauseData;
    TextureData *texButtonPlayData;
    TextureData *texButtonModeBallData;
    TextureData *texButtonModeConeData;
    TextureData *texButtonBombData;

    CometTextureData *cometData;

#endif  // SMASHMINER_CONFIG_USE_OPENGL_ES_2

//////////////////////////////////////////////////////////////////////////

private slots:

#ifdef SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE
    void enterRewindMode();
#endif

private:

    GameSettings *settings;

#ifdef SMASHMINER_CONFIG_ENABLE_ROTATION_SENSOR
    RotationSensor rotationSensor;
#endif

#ifdef SMASHMINER_CONFIG_ENABLE_ACCELERATION_SENSOR
    AccelometerSensor accelometerSensor;
#endif

    GameEngine *engine;
    SoundEngine *soundEngine;

    /*! If set to true OpenGL graphics are rendered with shader programs enabling black hole
        effect
     */
    bool paintWithBlackHole;

    bool isPaused;
    bool isMainMenuActive;

    bool isGameOver;

    QTime time;
    /*! For storing time measurements on each game cycle. 
     * #MSECS_BUFF_SIZE timer measurements are stored at once. 
     * Each game cycle time step is based on average value of the stored measurements.
     */
    int millisecondsArray[MSECS_BUFF_SIZE];
    /// Counts items in \c GameWidget::millisecondsArray, cannot be larger than #MSECS_BUFF_SIZE 
    int millisecondsCounter;

    enum { x, y, z };

    bool lefthanded;

    GLfloat spaceshipConeColorData[4];
    GLfloat spaceshipConeVertexData[SPACESHIP_CONE_INDICES];
    GLfloat spaceshipConeNormalData[SPACESHIP_CONE_INDICES];
    GLfloat spaceshipBallColorData[4];
    GLfloat spaceshipBallVertexData[SPACESHIP_BALL_INDICES];
    GLfloat spaceshipBallNormalData[SPACESHIP_BALL_INDICES];

    // Spaceship ball mode points.
    // The initial values are stored in these and they will be used
    // for adapting the spaceship graphics.
    GLfloat balBC[3];
    GLfloat balB1[3];
    GLfloat balB2[3];
    GLfloat balB3[3];
    GLfloat balB4[3];
    GLfloat balB5[3];
    GLfloat balB6[3];
    GLfloat balB7[3];
    GLfloat balB8[3];

    // Spaceship cone mode points
    GLfloat conCe[3];
    GLfloat conA0[3];
    GLfloat conB0[3];
    GLfloat conC0[3];
    GLfloat conD0[3];
    GLfloat conA1[3];
    GLfloat conA2[3];
    GLfloat conB1[3];
    GLfloat conB2[3];
    GLfloat conC1[3];
    GLfloat conC2[3];
    GLfloat conD1[3];
    GLfloat conD2[3];

    // Vertex arrays for storing vertex data for OpenGL game objects

    GLfloat asteroidVertexData[ASTEROID_INDICES];
    GLfloat asteroidNormalData[ASTEROID_INDICES];
    GLfloat asteroidColourData[ASTEROID_INDICES];

    GLfloat asteroidMediumAVertexData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumANormalData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumAColourData[ASTEROID_MEDIUM_INDICES];

    GLfloat asteroidMediumBVertexData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumBNormalData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumBColourData[ASTEROID_MEDIUM_INDICES];

    GLfloat asteroidMediumCVertexData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumCNormalData[ASTEROID_MEDIUM_INDICES];
    GLfloat asteroidMediumCColourData[ASTEROID_MEDIUM_INDICES];

    GLfloat mineralVertexData[MINERAL_INDICES];
    GLfloat mineralNormalData[MINERAL_INDICES];
    GLfloat mineralAColourData[4];
    GLfloat mineralBColourData[4];
    GLfloat mineralCColourData[4];
    GLfloat mineralDColourData[4];

    GLfloat ufoColor1ColorData[4];
    GLfloat ufoColor1VertexData[UFO_COLOR1_INDICES];
    GLfloat ufoColor1NormalData[UFO_COLOR1_INDICES];
    GLfloat ufoColor2ColorData[4];
    GLfloat ufoColor2VertexData[UFO_COLOR2_INDICES];
    GLfloat ufoColor2NormalData[UFO_COLOR2_INDICES];
    GLfloat ufoLightsColorData[4];
    GLfloat ufoLightsVertexData[UFO_LIGHTS_INDICES];
    GLfloat ufoLightsNormalData[UFO_LIGHTS_INDICES];

    /*! Stores vertex data for missile graphics object, the amount of indices is defined in
        #MISSILE_INDICES. Each vertex consists of three coordinate values (consumes three indices).
     */
    GLfloat missileVertexData[MISSILE_INDICES];
    /*! Stores normal data for vertex in \c GameWidget::missileVertexData. Each normal point
        consists of three coordinate values (consumes three indices).
     */
    GLfloat missileNormalData[MISSILE_INDICES];
    /// Stores missile colour data (red, green, blue and alpha values).
    GLfloat missileColourData[4];

    GLfloat bhParticlesXAxis[3];
    GLfloat bhParticlesYAxis[3];

    void initSpaceShip();
    void initAsteroid();
    void initMineral();
    void initUfo(GLfloat *ufoColor1Data, GLfloat *ufoColor1NormalData,
                 GLfloat *ufoColor2Data,GLfloat *ufoColor2NormalData,
                 GLfloat *ufoLightsData, GLfloat *ufoLightsNormalData);
    void initMissile();

    void randomRed(GLfloat *color);
    void randomGray(GLfloat *color);
    void randomBrown(GLfloat *color);

    void verticesToNormals(int indices, GLfloat *vertex, GLfloat *normal);
    void computeNormalForTriangle(GLfloat *normalValue, GLfloat *point1, GLfloat *point2, GLfloat *point3);
    void computeNormalForVectors(GLfloat *normalValue, GLfloat *vector1, GLfloat *vector2);

    GLfloat *vertexDataByType(const GameObject *gameObject);
    GLfloat *normalDataByType(const GameObject *gameObject);
    GLfloat *colourDataByType(const GameObject *gameObject);
    void ambientLmDataByType(const GameObject *gameObject, QVector4D &vector);
    void diffuseLmDataByType(const GameObject *gameObject, QVector4D &vector);
    void indexCountByType(const GameObject *gameObject, int &indexCount);

    void setSpaceShipVertexData(GLfloat shipAnimationPhase = 0);

    bool isObjectVisible(GameObject *gameObject);
    void getObjectPosition(GameObject *gameObject, GLfloat *position);

#ifdef SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE

    void cycleRewindMode(FPtype timeStep);
    void leaveRewindMode();

    /// Is in rewind playback mode? (true)
    bool rewindMode;

    /// First rewind playback frame
    int rewindFirstFrame;

    /// Last rewind playback frame
    int rewindLastFrame;

    /// Current rewind playback frame
    int rewindCurrentFrame;

    /// Iterator for rewind frames in rewind playback mode
    QQueue<FrameInfo *>::const_iterator rewindCurrentFrameInfo;

#ifdef  SMASHMINER_CONFIG_ENABLE_DEBUG_CHECKS

    QTime rewindClock;

#endif  // SMASHMINER_CONFIG_ENABLE_DEBUG_CHECKS
#endif  // SMASHMINER_CONFIG_ENABLE_GAME_REWIND_MODE

#ifdef SMASHMINER_CONFIG_ENABLE_FPS_PROFILING
    /// File for writing profiling data to
    QFile *profileFile;
    /// Text stream for the profiling data will be written to \c GameWidget::profileFile
    QTextStream *profileTextStream;
    Statistics worstFrameStats;
    int worstFrameNumber;
#endif  // SMASHMINER_CONFIG_ENABLE_FPS_PROFILING

};

#endif // GAMEWIDGET_H
